/** ****************************************************************************
 * @file 	modbus.hpp
 * @author 	mojinpan
 * @copyright (c) 2022-20xx, mojinpan All rights reserved.
 * @brief 	Modbus协议C++封装
 * @version 	V1.0
 * @date 	2025-6-14
 *******************************************************************************/
#ifndef __MODBUS_CPP_H_
#define __MODBUS_CPP_H_

#include <cstdint>
#include "modbus.h"

/**
 * @brief 通信端口抽象接口（支持多实例共享）
 * @details 所有具体通信实现需通过context参数区分不同Modbus实例的调用
 */
class ModbusPort
{
public:
    virtual ~ModbusPort() = default; // 虚析构保证多态释放

    /**
     * @brief 接收数据（带实例上下文）
     * @param cxt 调用此方法的Modbus实例指针（Master或Slave）
     * @param buf 接收缓冲区指针
     * @param len 期望接收的最大字节数
     * @return 实际接收的字节数（-1表示错误）
     */
    virtual int recv(void *cxt, uint8_t *buf, size_t len) = 0;

    /**
     * @brief 发送数据（带实例上下文）
     * @param cxt 调用此方法的Modbus实例指针（Master或Slave）
     * @param buf 发送缓冲区指针
     * @param len 待发送的字节数
     * @return 实际发送的字节数（-1表示错误）
     */
    virtual int send(void *cxt, const uint8_t *buf, size_t len) = 0;
};

/**
 * @brief Modbus主机类
 */
class MbusMaster
{
    ModbusMaster_t m_cObj;        // 保留原C结构体作为内部状态
    ModbusPort *m_port = nullptr; // 新增：C++通信接口指针

public:
    /**
     * @brief 构造函数（直接初始化C结构体）
     * @param mode Modbus协议模式（MODBUS_RTU/MODBUS_TCP等）
     * @param addrOrId 从机地址或单元标识符
     * @return 初始化结果（MODBUS_OK或错误码）
     */
    ModbusInfo_t init(MbusMode_t mode, uint8_t addrOrId)
    {
        return Modbus_MasterInit(&m_cObj, mode, addrOrId);
    }

    /**
     * @brief 设置通信端口（C++接口绑定）
     * @param port 具体通信实现对象（需保持生命周期）
     */
    void setPort(ModbusPort *port)
    {
        m_port = port;
        // 将C++接口的recv/send绑定到C库的函数指针，传递当前Master实例作为context
        m_cObj.port.recv = [](void *cxt, uint8_t *buf, size_t len)
        {
            MbusMaster *master = static_cast<MbusMaster *>(cxt); // cxt指向当前Master实例
            return master->m_port->recv(master, buf, len);       // 传递master指针作为context
        };
        m_cObj.port.send = [](void *cxt, uint8_t *buf, size_t len)
        {
            MbusMaster *master = static_cast<MbusMaster *>(cxt);
            return master->m_port->send(master, buf, len); // 传递master指针作为context
        };
        m_cObj.cxt = this; // 上下文指向当前ModbusMaster实例
    }

    /**
     * @brief 设置功能码处理函数（直接操作C结构体）
     * @param id 功能码ID
     * @param request 请求处理函数（C函数指针）
     * @param response 响应处理函数（C函数指针）
     * @return 设置结果（MODBUS_OK或错误码）
     */
    ModbusInfo_t setFunction(uint8_t id, modusFunc_t request, modusFunc_t response)
    {
        return Modbus_MasterFuncSet(&m_cObj, id, request, response);
    }

    /**
     * @brief 读取寄存器（直接调用C库函数）
     * @param type 寄存器类型（MODBUS_REG_0x/1x/3x/4x）
     * @param addr 起始地址（0-based）
     * @param cnt 读取数量（最大255）
     * @param[out] buf 数据缓冲区（需预分配至少cnt*2字节）
     * @return 读取结果（MODBUS_OK或错误码）
     */
    ModbusInfo_t read(ModbusDataType_t type, uint16_t addr, uint16_t cnt, uint16_t *buf)
    {
        return Modbus_MasterRead(&m_cObj, type, addr, cnt, buf);
    }

    /**
     * @brief 写入寄存器（直接调用C库函数）
     * @param type 寄存器类型（MODBUS_REG_0x/1x/3x/4x）
     * @param addr 起始地址（0-based）
     * @param[in] buf 数据缓冲区（需预分配至少cnt*2字节）
     * @return 写入结果（MODBUS_OK或错误码）
     */
    ModbusInfo_t write(ModbusDataType_t type, uint16_t addr, uint16_t cnt, uint16_t *buf)
    {
        return Modbus_MasterWrite(&m_cObj, type, addr, cnt, buf);
    }
    /**
     * @brief 执行功能码（直接调用C库函数）
     * @param id 功能码ID
     * @param buf 数据缓冲区（根据功能码不同）
     * @return 执行结果（MODBUS_OK或错误码）
     */
    ModbusInfo_t func(uint8_t func, uint16_t idx, uint16_t cnt, uint16_t *reg)
    {
        return Modbus_MasterFunc(&m_cObj, func, idx, cnt, reg);
    }
};

/**
 * @brief Modbus从机类
 */
class MbusSlave
{
    ModbusSlave_t m_cObj;         // 保留原C结构体作为内部状态
    ModbusPort *m_port = nullptr; // 新增：C++通信接口指针

public:
    /**
     * @brief 构造函数（直接初始化C结构体）
     * @param mode Modbus协议模式（MODBUS_RTU/MODBUS_TCP等）
     * @param addr 从机地址（1-247）
     * @return 初始化结果（MODBUS_OK或错误码）
     */
    ModbusInfo_t init(MbusMode_t mode, uint8_t addr)
    {
        return Modbus_SlaveInit(&m_cObj, mode, addr);
    }

    /**
     * @brief 设置通信端口（C++接口绑定）
     * @param port 具体通信实现对象（需保持生命周期）
     */
    void setPort(ModbusPort *port)
    {
        m_port = port;
        // 将C++接口的recv/send绑定到C库的函数指针，传递当前Slave实例作为context
        m_cObj.port.recv = [](void *cxt, uint8_t *buf, size_t len)
        {
            MbusSlave *slave = static_cast<MbusSlave *>(cxt); // cxt指向当前Slave实例
            return slave->m_port->recv(slave, buf, len);      // 传递slave指针作为context
        };
        m_cObj.port.send = [](void *cxt, uint8_t *buf, size_t len)
        {
            MbusSlave *slave = static_cast<MbusSlave *>(cxt);
            return slave->m_port->send(slave, buf, len); // 传递slave指针作为context
        };
        m_cObj.cxt = this; // 上下文指向当前ModbusSlave实例
    }

    /**
     * @brief 设置功能码处理函数（直接操作C结构体）
     * @param id 功能码ID
     * @param request 请求处理函数（C函数指针）
     * @param response 响应处理函数（C函数指针）
     * @return 设置结果（MODBUS_OK或错误码）
     */
    ModbusInfo_t setFunction(uint8_t id, modusFunc_t response)
    {
        return Modbus_SlaveFuncSet(&m_cObj, id, response);
    }
    /**
     * @brief 设置寄存器读回调（直接操作C结构体）
     * @param callback 读回调函数（参数：上下文指针，寄存器类型，起始地址，值指针）
     */
    void setReadCallback(int (*callback)(void *, uint8_t, uint16_t, uint16_t *))
    {
        m_cObj.readCallback = callback;
    }

    /**
     * @brief 设置寄存器写回调（直接操作C结构体）
     * @param callback 写回调函数（参数：上下文指针，寄存器类型，目标地址，值）
     */
    void setWriteCallback(int (*callback)(void *, uint8_t, uint16_t, uint16_t))
    {
        m_cObj.writeCallback = callback;
    }

    /**
     * @brief 处理接收到的请求（需在主循环或独立线程中调用）
     * @details 该函数为同步处理，建议：
     *          - 单线程场景：在主循环中周期性调用
     *          - 多线程场景：在独立线程中循环调用
     * @return 处理结果（MODBUS_OK或错误码）
     */
    ModbusInfo_t processRequest()
    {
        return Modbus_SlaveTask(&m_cObj);
    }
};

#endif // __MODBUS_CPP_H_